package cn.trigram.date;

import cn.trigram.exception.DateFormatException;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;

/**
 * 使用Java8 LocalDateTime时间体系处理
 * <br/>
 * 默认的时间日期格式为广发使用广泛的为主：yyyyMMddHHmmss、yyyyMMdd、HHmmss
 * <br/>
 * 常用方法：
 * <ol>
 *     <li>
 *         {@link #parse(String)}
 *         <ul>
 *             <li>懒人方法，自动判断以下八种格式的字符串:yyyyMMddHHmmss、yyyyMMdd、yyy-MM-dd HH:mm:ss、yyy-MM-dd、
 *             yyy/MM/dd HH:mm:ss、yyy/MM/dd、yyy\MM\dd HH:mm:ss、yyy\MM\dd</li>
 *         </ul>
 *     </li>
 *     <li>parseXXX</li>
 *     <li>formatXXX</li>
 *     <li>
 *         {@link #adjuster(Date)}
 *         <ul>
 *             <li>获取日期调整器，通过链式调用形式进行不同时间单位的调整，或者调整至特殊时刻</li>
 *         </ul>
 *     </li>
 *     <li>
 *         {@link #resolver(Date)}
 *         <ul>
 *             <li>获取时间日期解析器，解析日期时间的不同单位，或者特殊时间段数据</li>
 *         </ul>
 *     </li>
 *     <li>{@link #calculator(Date, Date)} </li>
 * </ol>
 * <b>
 * 注：
 * <br/>如果调整时间，用{@link #adjuster(Date)}方法；
 * <br/>如果判断给定日期时间的所在季度等信息，用{@link #resolver(Date)}；
 * <br/>如果对两个日期时间的计算，用{@link #calculator(Date, Date)}方法
 * </b>
 *
 * @version 1.0.0
 * @date 2022/07/22 14:38:58
 * @since 1.0.0
 */
public class DateUtil {

  /**
   * GF默认日期格式：yyyyMMdd
   */
  public final static String GF_DEFAULT_SHORT = "yyyyMMdd";

  /**
   * GF默认时间格式：HHmmss
   */
  public final static String GF_DEFAULT_TIME = "HHmmss";

  /**
   * GF默认日期时间格式：yyyyMMddHHmmss
   */
  public final static String GF_DEFAULT_FULL = "yyyyMMddHHmmss";

  /**
   * 斜杠的日期时间格式：yyyy/MM/dd HH:mm:ss
   */
  public final static String RIGHT_SLASH_FORMAT_FULL = "yyyy/MM/dd HH:mm:ss";

  /**
   * 反斜杠的日期时间格式：yyyy\MM\dd HH:mm:ss
   */
  public final static String LEFT_SLASH_FORMAT_FULL = "yyyy\\MM\\dd HH:mm:ss";

  /**
   * 斜杠的日期格式：yyyy/MM/dd
   */
  public final static String RIGHT_SLASH_FORMAT_SHORT = "yyyy/MM/dd";

  public final static String SHORT_MONTH_RIGHT_SLASH_FORMAT = "yyyy/M/dd";

  public final static String SHORT_DAY_RIGHT_SLASH_FORMAT = "yyyy/MM/d";

  public final static String SHORT_MONTH_AND_DAY_RIGHT_SLASH_FORMAT = "yyyy/M/d";

  /**
   * 反斜杠的日期格式：yyyy\\MM\\dd
   */
  public final static String LEFT_SLASH_FORMAT_SHORT = "yyyy\\MM\\dd";

  public final static String SHORT_MONTH_LEFT_SLASH_FORMAT = "yyyy\\M\\dd";

    public final static String SHORT_DAY_LEFT_SLASH_FORMAT = "yyyy\\MM\\d";

  public final static String SHORT_MONTH_AND_DAY_LEFT_SLASH_FORMAT = "yyyy\\M\\d";

  /**
   * 横杠的日期时间格式：yyyy-MM-dd HH:mm:ss
   */
  public final static String DASH_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss";

    /**
     * 横杠的日期格式：yyyy-MM-dd
     */
    public final static String DASH_FORMAT_SHORT = "yyyy-MM-dd";

  public final static String SHORT_MONTH_DASH_FORMAT = "yyyy-M-dd";

  public final static String SHORT_DAY_DASH_FORMAT = "yyyy-MM-d";

  public final static String SHORT_MONTH_AND_DAY_DASH_FORMAT = "yyyy-M-d";

  /**
   * 时间格式
   */
  public final static String FORMAT_TIME = "HH:mm:ss";

  /**
   * 用作格式器的缓存
   */
  public final static Map<String, DateTimeFormatter> FORMATTER_MAP = new ConcurrentHashMap<>();

  /**
   * 判断HH:mm:ss 时间格式
   */
  public final static Pattern TIME_PATTERN = Pattern.compile("\\d{2}:\\d{2}:\\d{2}");

  /**
   * 判断yyyy[-/\]MM[-/\]dd 这类日期格式
   */
  public final static Pattern DATE_PATTERN = Pattern.compile("\\d{4}([-\\\\/]+)\\d{1,2}([-\\\\/]+)\\d{1,2}");

  /**
   * 判断yyyy[-/\]MM[-/\]dd 这类日期格式
   */
  public final static Pattern FULL_DATE_PATTERN = Pattern.compile("\\d{4}([-\\\\/])\\d{2}([-\\\\/])\\d{2}");

  /**
   * 判断yyyy[-/\]M[-/\]dd 这类日期格式
   */
  public final static Pattern SHORT_MONTH_DATE_PATTERN = Pattern.compile("\\d{4}([-\\\\/])\\d([-\\\\/])\\d{2}");

  /**
   * 判断yyyy[-/\]MM[-/\]d 这类日期格式
   */
  public final static Pattern SHORT_DAY_DATE_PATTERN = Pattern.compile("\\d{4}([-\\\\/])\\d{2}([-\\\\/])\\d");

  /**
   * 判断yyyy[-/\]M[-/\]d 这类日期格式
   */
  public final static Pattern SHORT_MONTH_AND_DAY_DATE_PATTERN = Pattern.compile("\\d{4}([-\\\\/])\\d([-\\\\/])\\d");

  /**
   * 判断yyyy[-/\]MM[-/\]dd HH:mm:ss这类日期时间格式
   */
  public final static Pattern DATETIME_PATTERN = Pattern.compile(
      "\\d{4}([-\\\\/]+)\\d{1,2}([-\\\\/]+)\\d{1,2}\\s+\\d{2}:\\d{2}:\\d{2}");

  /**
   * 判断HHmmss，GF默认的时间格式
   */
  public final static Pattern GF_TIME_PATTERN = Pattern.compile("^\\d{6}$");

  /**
   * 判断yyyyMMdd，GF默认的日期格式
   */
  public final static Pattern GF_DATE_PATTERN = Pattern.compile("^\\d{8}$");

  /**
   * 判断yyyyMMddHHmmss，GF默认的日期时间格式
   */
  public final static Pattern GF_DATETIME_PATTERN = Pattern.compile("^\\d{14}$");

  public final static DateTimeFormatter GF_DEFAULT_SHORT_FORMATTER = DateTimeFormatter.ofPattern(GF_DEFAULT_SHORT);

  public final static DateTimeFormatter GF_DEFAULT_TIME_FORMATTER = DateTimeFormatter.ofPattern(GF_DEFAULT_TIME);

  public final static DateTimeFormatter GF_DASH_FORMAT_SHORT_FORMATTER = DateTimeFormatter.ofPattern(DASH_FORMAT_SHORT);

  /**
   * 时间格式器
   *
   * @return {@link DateTimeFormatter }
   */
  public static DateTimeFormatter formatter(String format) {

    return formatter(format, JsonFormat.DEFAULT_LOCALE, JsonFormat.DEFAULT_TIMEZONE);
    }

    /**
     * 时间格式器
     *
     * @param format
     * @return {@link DateTimeFormatter }
     */
    public static DateTimeFormatter formatter(String format, String localeStr, String timezoneStr) {

      final String key = format + ":" + localeStr + ":" + timezoneStr;
      if (FORMATTER_MAP.containsKey(key)) {
        return FORMATTER_MAP.get(key);
      }
      final Locale      locale            =
          StringUtils.equals(localeStr, JsonFormat.DEFAULT_LOCALE) || StringUtils.isBlank(localeStr)
          ? Locale.getDefault() : new Locale(localeStr);
      DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format, locale);
      if (!StringUtils.equals(timezoneStr, JsonFormat.DEFAULT_TIMEZONE) && StringUtils.isNotBlank(timezoneStr)) {
        dateTimeFormatter = dateTimeFormatter.withZone(TimeZone.getTimeZone(timezoneStr).toZoneId());
      }
      FORMATTER_MAP.put(key, dateTimeFormatter);
      return dateTimeFormatter;
    }

  /**
   * 解析指定格式的日期时间
   */
  public static LocalDateTime parseDateTime(String dateTimeStr, DateTimeFormatter formatter) {

    if (StringUtils.isBlank(dateTimeStr)) {
      throw new IllegalArgumentException("日期时间不能为空");
    }
    return LocalDateTime.parse(dateTimeStr, formatter);
  }

  /**
   * 解析指定格式的日期时间
   */
  public static LocalDateTime parseDateTime(String dateTimeStr, String format) {

    return parseDateTime(dateTimeStr, formatter(format));
  }

  /**
   * 解析yyyyMMddHHmmss格式的日期时间
   */
  public static LocalDateTime parseDateTime(String dateTimeStr) {

    return parseDateTime(dateTimeStr, GF_DEFAULT_FULL);
  }

  /**
   * 解析指定格式的日期
   */
  public static LocalDate parseDate(String dateStr, DateTimeFormatter formatter) {

    if (StringUtils.isBlank(dateStr)) {
      throw new IllegalArgumentException("日期不能为空");
    }
    return LocalDate.parse(dateStr, formatter);
  }

  /**
   * 解析指定格式的日期
   */
  public static LocalDate parseDate(String dateStr, String format) {

    return parseDate(dateStr, formatter(format));
  }

  /**
   * 解析yyyyMMdd 格式的日期
   *
   * @return {@link LocalDate }
   */
  public static LocalDate parseDate(String dateStr) {

    return parseDate(dateStr, GF_DEFAULT_SHORT);
  }

  public static LocalDate parseDate(int date, String format) {

    return parseDate(date, formatter(format));
  }

  public static LocalDate parseDate(int date, DateTimeFormatter formatter) {

    return parseDate(String.valueOf(date), formatter);
  }

  /**
   * 解析指定格式的时间
   */
  public static LocalTime parseTime(String timeStr, DateTimeFormatter formatter) {

    if (StringUtils.isBlank(timeStr)) {
      throw new IllegalArgumentException("时间不能为空");
    }
    return LocalTime.parse(timeStr, formatter);
  }

  /**
   * 解析指定格式的时间
   */
  public static LocalTime parseTime(String timeStr, String format) {

    return parseTime(timeStr, formatter(format));
  }

  /**
   * 解析HHmmss格式的时间
   */
  public static LocalTime parseTime(String timeStr) {

    return parseTime(timeStr, GF_DEFAULT_TIME);
    }


    /**
     * 格式化指定格式的日期时间
     *
     * @return {@link String }
     */
    public static String formatDateTime(Date d, DateTimeFormatter formatter) {
        if (Objects.isNull(d)) {
            throw new IllegalArgumentException("日期时间不能为空");
        }
      return d.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter);
    }

  /**
   * 格式化指定格式的日期时间
   *
   * @return {@link String }
   */
  public static String formatDateTime(Date d, String format) {

    return formatDateTime(d, formatter(format));
  }


  /**
   * 格式化yyyyMMddHHmmss格式的日期时间
   *
   * @return {@link String }
   */
  public static String formatDateTime(Date d) {

    return formatDateTime(d, GF_DEFAULT_FULL);
  }

  /**
   * 格式化指定格式的日期
   *
   * @return {@link String }
   */
  public static String formatDate(Date d, DateTimeFormatter formatter) {

    if (Objects.isNull(d)) {
      throw new IllegalArgumentException("日期不能为空");
    }
    return d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(formatter);
  }

  /**
   * 格式化指定格式的日期
   *
   * @return {@link String }
   */
  public static String formatDate(Date d, String format) {

    return formatDate(d, formatter(format));
  }

  /**
   * 格式化yyyyMMdd 格式的日期
   *
   * @return {@link String }
   */
  public static String formatDate(Date d) {

    return formatDate(d, GF_DEFAULT_SHORT);
  }

  /**
   * 格式化指定格式的时间
   *
   * @return {@link String }
   */
  public static String formatTime(Date d, DateTimeFormatter formatter) {

    if (Objects.isNull(d)) {
      throw new IllegalArgumentException("时间不能为空");
    }
    return d.toInstant().atZone(ZoneId.systemDefault()).toLocalTime().format(formatter);
  }


  /**
   * 格式化指定格式的时间
   *
   * @return {@link String }
   */
  public static String formatTime(Date d, String format) {

    return formatTime(d, formatter(format));
  }

  /**
   * 格式化HHmmss 格式的日期
   *
   * @return {@link String }
   */
  public static String formatTime(Date d) {

    return formatTime(d, GF_DEFAULT_TIME);
  }

  /**
   * 格式为{@link #GF_DEFAULT_FULL}的日期的不同时间单位数值增加
   *
   * @param dateStr
   *     日期字符串
   * @param years
   *     年份
   * @param months
   *     月份
   * @param days
   *     天数
   * @param hours
   *     小时数
   * @param minutes
   *     分钟数
   * @param seconds
   *     秒数
   * @param millis
   *     毫秒数
   * @param nanos
   *     纳秒数
   *
   * @return {@link String }
   */
  public static String plusOfDateTime(
      String dateStr, int years, int months, int days, int hours, int minutes, int seconds, int millis, int nanos
  ) {

    return new DateTimeAdjuster(parse(dateStr))
        .plusYear(years).plusMonth(months).plusDay(days)
        .plusHour(hours).plusMinute(minutes).plusSecond(seconds)
        .plusMillis(millis).plusNanos(nanos)
        .toLocalDateTime().format(formatter(GF_DEFAULT_FULL));
  }

  /**
   * 文档查看：{@link #plusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String plusYearOfDateTime(String dateStr, int years) {

    return plusOfDateTime(dateStr, years, 0, 0, 0, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String plusMonthOfDateTime(String dateStr, int months) {

    return plusOfDateTime(dateStr, 0, months, 0, 0, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String plusDayOfDateTime(String dateStr, int days) {

    return plusOfDateTime(dateStr, 0, 0, days, 0, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String plusHourOfDateTime(String dateStr, int hours) {

    return plusOfDateTime(dateStr, 0, 0, 0, hours, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String plusMinutesOfDateTime(String dateStr, int minutes) {

    return plusOfDateTime(dateStr, 0, 0, 0, 0, minutes, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String plusSecondOfDateTime(String dateStr, int seconds) {
        return plusOfDateTime(dateStr, 0, 0, 0, 0, 0, seconds, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String plusMillisOfDateTime(String dateStr, int millis) {

    return new DateTimeAdjuster(parseDateTime(dateStr, GF_DEFAULT_FULL + ".SSS"))
        .plusMillis(millis)
        .toLocalDateTime().format(formatter(GF_DEFAULT_FULL + ".SSS"));
  }

  /**
   * 文档查看：{@link #plusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String plusNanosOfDateTime(String dateStr, int nanos) {

    return new DateTimeAdjuster(parseDateTime(dateStr, GF_DEFAULT_FULL + "nnnnnnnnn"))
        .plusNanos(nanos)
        .toLocalDateTime().format(formatter(GF_DEFAULT_FULL + "nnnnnnnnn"));
  }

  /**
   * 格式为{@link #GF_DEFAULT_SHORT}的日期的不同时间单位数值增加
   *
   * @param dateStr 日期字符串
   * @param years   年份
   * @param months  月份
   * @param days    天数
   * @return {@link String }
   */
  public static String plusOfDate(String dateStr, int years, int months, int days) {

    return new DateTimeAdjuster(parse(dateStr))
        .plusYear(years).plusMonth(months).plusDay(days)
        .toLocalDate().format(formatter(GF_DEFAULT_SHORT));
  }

  /**
   * 文档查看：{@link #plusOfDate(String, int, int, int)}
   */
  public static String plusYearOfDate(String dateStr, int years) {

    return plusOfDate(dateStr, years, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfDate(String, int, int, int)}
   */
  public static String plusMonthOfDate(String dateStr, int months) {

    return plusOfDate(dateStr, 0, months, 0);
  }

  /**
   * 获取一个日期向前或向后推移若干天的日期
   *
   * @param date 基准日期
   * @param days 推移天数，大于0表示向后推移，小于0表示向前推移
   * @return 日期向前或向后推移若干天的日期
   */
  public static int offset(int date, int days) {

    if (days == 0) {
      return date;
    }

    LocalDate localDate = LocalDate.parse(String.valueOf(date), GF_DEFAULT_SHORT_FORMATTER);
    LocalDate offsetLocalDate;
    offsetLocalDate = localDate.plusDays(days);
    String offsetDateString = offsetLocalDate.format(GF_DEFAULT_SHORT_FORMATTER);

    return Integer.parseInt(offsetDateString);
  }

  /**
   * 文档查看：{@link #plusOfDate(String, int, int, int)}
   */
  public static String plusDayOfDate(String dateStr, int days) {

    return plusOfDate(dateStr, 0, 0, days);
  }

  /**
   * 格式为{@link #GF_DEFAULT_TIME}的日期的不同时间单位数值增加
   *
   * @param dateStr
   *     日期字符串
   * @param hours
   *     小时数
   * @param minutes
   *     分钟数
   * @param seconds
   *     秒数
   * @param millis
   *     毫秒数
   * @param nanos
   *     纳秒数
   *
   * @return {@link String }
   */
  public static String plusOfTime(String dateStr, int hours, int minutes, int seconds, int millis, int nanos) {

    return new DateTimeAdjuster(parse(dateStr))
        .plusHour(hours).plusMinute(minutes).plusSecond(seconds)
        .plusMillis(millis).plusNanos(nanos)
        .toLocalTime().format(formatter(GF_DEFAULT_TIME));
  }

  /**
   * 文档查看：{@link #plusOfTime(String, int, int, int, int, int)}
   */
  public static String plusHourOfTime(String dateStr, int hours) {

    return plusOfTime(dateStr, hours, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfTime(String, int, int, int, int, int)}
   */
  public static String plusMinutesOfTime(String dateStr, int minutes) {

    return plusOfTime(dateStr, 0, minutes, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfTime(String, int, int, int, int, int)}
   */
  public static String plusSecondOfTime(String dateStr, int seconds) {

    return plusOfTime(dateStr, 0, 0, seconds, 0, 0);
  }

  /**
   * 文档查看：{@link #plusOfTime(String, int, int, int, int, int)}
   */
  public static String plusMillisOfTime(String dateStr, int millis) {

    return new DateTimeAdjuster(parseTime(dateStr, GF_DEFAULT_TIME + ".SSS"))
        .plusMillis(millis)
        .toLocalTime().format(formatter(GF_DEFAULT_TIME + ".SSS"));
  }

  /**
   * 文档查看：{@link #plusOfTime(String, int, int, int, int, int)}
   */
  public static String plusNanosOfTime(String dateStr, int nanos) {

    return new DateTimeAdjuster(parseTime(dateStr, GF_DEFAULT_TIME + "nnnnnnnnn"))
        .plusNanos(nanos)
        .toLocalTime().format(formatter(GF_DEFAULT_TIME + "nnnnnnnnn"));
  }

  /**
   * 格式为{@link #GF_DEFAULT_FULL}的日期的不同时间单位数值减少
   *
   * @param dateStr 日期字符串
   * @param years   年份
   * @param months  月份
   * @param days    天数
   * @param hours   小时数
   * @param minutes 分钟数
   * @param seconds 秒数
   * @param millis  毫秒数
   * @param nanos   纳秒数
   * @return {@link String }
   */
  public static String minusOfDateTime(
      String dateStr, int years, int months, int days, int hours, int minutes, int seconds, int millis, int nanos
  ) {

    return new DateTimeAdjuster(parse(dateStr))
        .minusYear(years).minusMonth(months).minusDay(days)
        .minusHour(hours).minusMinute(minutes).minusSecond(seconds)
        .minusMillis(millis).minusNanos(nanos)
        .toLocalDateTime().format(formatter(GF_DEFAULT_FULL));
  }

  /**
   * 文档查看：{@link #minusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String minusYearOfDateTime(String dateStr, int years) {

    return minusOfDateTime(dateStr, years, 0, 0, 0, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String minusMonthOfDateTime(String dateStr, int months) {

    return minusOfDateTime(dateStr, 0, months, 0, 0, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String minusDayOfDateTime(String dateStr, int days) {

    return minusOfDateTime(dateStr, 0, 0, days, 0, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String minusHourOfDateTime(String dateStr, int hours) {

    return minusOfDateTime(dateStr, 0, 0, 0, hours, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String minusMinutesOfDateTime(String dateStr, int minutes) {

    return minusOfDateTime(dateStr, 0, 0, 0, 0, minutes, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String minusSecondOfDateTime(String dateStr, int seconds) {

    return minusOfDateTime(dateStr, 0, 0, 0, 0, 0, seconds, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String minusMillisOfDateTime(String dateStr, int millis) {

    return new DateTimeAdjuster(parseDateTime(dateStr, GF_DEFAULT_FULL + ".SSS"))
        .minusMillis(millis)
        .toLocalDateTime().format(formatter(GF_DEFAULT_FULL + ".SSS"));
  }

  /**
   * 文档查看：{@link #minusOfDateTime(String, int, int, int, int, int, int, int, int)}
   */
  public static String minusNanosOfDateTime(String dateStr, int nanos) {

    return new DateTimeAdjuster(parseDateTime(dateStr, GF_DEFAULT_FULL + "nnnnnnnnn"))
        .minusNanos(nanos)
        .toLocalDateTime().format(formatter(GF_DEFAULT_FULL + "nnnnnnnnn"));
  }

  /**
   * 格式为{@link #GF_DEFAULT_SHORT}的日期的不同时间单位数值减少
   *
   * @param dateStr 日期字符串
   * @param years   年份
   * @param months  月份
   * @param days    天数
   * @return {@link String }
   */
  public static String minusOfDate(String dateStr, int years, int months, int days) {

    return new DateTimeAdjuster(parse(dateStr))
        .minusYear(years).minusMonth(months).minusDay(days)
        .toLocalDate().format(formatter(GF_DEFAULT_SHORT));
  }

  /**
   * 文档查看：{@link #minusOfDate(String, int, int, int)}
   */
  public static String minusYearOfDate(String dateStr, int years) {

    return minusOfDate(dateStr, years, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfDate(String, int, int, int)}
   */
  public static String minusMonthOfDate(String dateStr, int months) {

    return minusOfDate(dateStr, 0, months, 0);
  }

  /**
   * 文档查看：{@link #minusOfDate(String, int, int, int)}
   */
  public static String minusDayOfDate(String dateStr, int days) {

    return minusOfDate(dateStr, 0, 0, days);
  }

  /**
   * 格式为{@link #GF_DEFAULT_TIME}的日期的不同时间单位数值减少
   *
   * @param dateStr 日期字符串
   * @param hours   小时数
   * @param minutes 分钟数
   * @param seconds 秒数
   * @param millis  毫秒数
   * @param nanos   纳秒数
   * @return {@link String }
   */
  public static String minusOfTime(String dateStr, int hours, int minutes, int seconds, int millis, int nanos) {

    return new DateTimeAdjuster(parse(dateStr))
        .minusHour(hours).minusMinute(minutes).minusSecond(seconds)
        .minusMillis(millis).minusNanos(nanos)
        .toLocalTime().format(formatter(GF_DEFAULT_TIME));
  }

  /**
   * 文档查看：{@link #minusOfTime(String, int, int, int, int, int)}
   */
  public static String minusHourOfTime(String dateStr, int hours) {

    return minusOfTime(dateStr, hours, 0, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfTime(String, int, int, int, int, int)}
   */
  public static String minusMinutesOfTime(String dateStr, int minutes) {

    return minusOfTime(dateStr, 0, minutes, 0, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfTime(String, int, int, int, int, int)}
   */
  public static String minusSecondOfTime(String dateStr, int seconds) {

    return minusOfTime(dateStr, 0, 0, seconds, 0, 0);
  }

  /**
   * 文档查看：{@link #minusOfTime(String, int, int, int, int, int)}
   */
  public static String minusMillisOfTime(String dateStr, int millis) {

    return new DateTimeAdjuster(parseTime(dateStr, GF_DEFAULT_TIME + ".SSS"))
        .minusMillis(millis)
        .toLocalTime().format(formatter(GF_DEFAULT_TIME + ".SSS"));
  }

  /**
   * 文档查看：{@link #minusOfTime(String, int, int, int, int, int)}
   */
  public static String minusNanosOfTime(String dateStr, int nanos) {

    return new DateTimeAdjuster(parseTime(dateStr, GF_DEFAULT_TIME + "nnnnnnnnn")).minusNanos(nanos)
        .toLocalTime().format(formatter(GF_DEFAULT_TIME + "nnnnnnnnn"));
  }

  /**
   * @return boolean
   *
   * @see DateTimeCalculator#isNeq()
   */
  public static boolean neq(String dateStr1, String dateStr2) {

    return new DateTimeCalculator(parse(dateStr1), parse(dateStr2)).isNeq();
  }

  /**
   * @return boolean
   *
   * @see DateTimeCalculator#isEq()
   */
  public static boolean eq(String dateStr1, String dateStr2) {

    return new DateTimeCalculator(parse(dateStr1), parse(dateStr2)).isEq();
  }

  /**
   * @return boolean
   * @see DateTimeCalculator#isLt()
   */
  public static boolean lt(String dateStr1, String dateStr2) {

    return new DateTimeCalculator(parse(dateStr1), parse(dateStr2)).isLt();
  }

  /**
   * @return boolean
   * @see DateTimeCalculator#isLte()
   */
  public static boolean lte(String dateStr1, String dateStr2) {

    return new DateTimeCalculator(parse(dateStr1), parse(dateStr2)).isLte();
  }

  /**
   * @return boolean
   * @see DateTimeCalculator#isGt()
   */
  public static boolean gt(String dateStr1, String dateStr2) {

    return new DateTimeCalculator(parse(dateStr1), parse(dateStr2)).isGt();
  }

  /**
   * @return boolean
   * @see DateTimeCalculator#isGte()
   */
  public static boolean gte(String dateStr1, String dateStr2) {

    return new DateTimeCalculator(parse(dateStr1), parse(dateStr2)).isGte();
  }

  /**
   * 获取时间调整器
   *
   * @param d
   * @return {@link DateTimeAdjuster }
   */
  public static DateTimeAdjuster adjuster(Date d) {

    return new DateTimeAdjuster(d);
  }

  /**
   * 获取时间解析器
   *
   * @param d
   * @return {@link DateTimeResolver }
   */
  public static DateTimeResolver resolver(Date d) {

    return new DateTimeResolver(d);
  }

  /**
   * 获取时间区间计算器
   *
   * @return {@link DateTimeResolver }
   */
  public static DateTimeInterval interval(Date left1, Date right1, Date left2, Date right2) {

    return new DateTimeInterval(
        new DateTimeInterval.Interval(toLocalDateTime(left1), toLocalDateTime(right1)),
        new DateTimeInterval.Interval(toLocalDateTime(left2), toLocalDateTime(right2))
    );
  }

  /**
   * 获取时间计算器
   *
   * @param lessDate   较小时间
   * @param largerDate 较大时间
   * @return {@link DateTimeCalculator }
   */
  public static DateTimeCalculator calculator(Date lessDate, Date largerDate) {

    return new DateTimeCalculator(lessDate, largerDate);
  }

  public static LocalDateTime toLocalDateTime(Date d) {

    if (Objects.isNull(d)) {
      return null;
    }
    return d.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
  }

  public static Date toDate(LocalDateTime d) {

    if (Objects.isNull(d)) {
      return null;
    }
    return Date.from(d.atZone(ZoneId.systemDefault()).toInstant());
  }

  public static Date toDate(LocalDate d) {

    if (Objects.isNull(d)) {
      return null;
    }
    return Date.from(d.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
  }

  public static Date toDate(LocalTime d) {

    if (Objects.isNull(d)) {
      return null;
    }
    return Date.from(d.atDate(LocalDate.now()).atZone(ZoneId.systemDefault()).toInstant());
  }

  public static Date toDate(Temporal d) {

    if (Objects.isNull(d)) {
      return null;
    }
    if (d instanceof LocalDateTime) {
      return toDate((LocalDateTime) d);
    } else if (d instanceof LocalDate) {
      return toDate((LocalDate) d);
    } else if (d instanceof LocalTime) {
      return toDate((LocalTime) d);
    } else {
      return null;
    }
  }

  /**
   * 方便以数值类型接收yyyyMMddHHmmss格式的日期时间转换成日期对象
   *
   * @param d
   * @return {@link Date }
   */
  public static Date toDate(Number d) {

    if (Objects.isNull(d)) {
      return null;
    }
    return toDate(parse(String.valueOf(d)));
  }

  /**
   * 用于多种格式的解析。可以判断如下格式：
   * yyyyMMddHHmmss、yyyyMMdd、yyy-MM-dd HH:mm:ss、yyy-MM-dd、
   * yyy/MM/dd HH:mm:ss、yyy/MM/dd、yyy\MM\dd HH:mm:ss、yyy\MM\dd、
   * HHmmss、HH:mm:ss
   * <br/>
   * <b>注：如果是只有日期，则补上00:00:00；如果只有时间，则补上当日的日期</b>
   *
   * @param str
   * @return {@link LocalDateTime }
   */
  public static LocalDateTime parse(String str) {

    if (StringUtils.isBlank(str)) {
      return null;
    }

    Matcher matcher = GF_DATE_PATTERN.matcher(str);
    if (matcher.matches()) {
      return parseDate(str).atStartOfDay();
    }

    matcher = GF_DATETIME_PATTERN.matcher(str);
    if (matcher.matches()) {
      return parseDateTime(str);
    }

    matcher = GF_TIME_PATTERN.matcher(str);
    if (matcher.matches()) {
      return parseTime(str).atDate(LocalDate.now());
    }

    //这里两个Pattern的匹配顺序不能错，要保证先匹配长的模式
    matcher = DATETIME_PATTERN.matcher(str);
    if (matcher.matches()) {
      final String joinSymbol = matcher.group(1);
      switch (joinSymbol) {
        case "-":
          return parseDateTime(str, DASH_FORMAT_FULL);
        case "/":
          return parseDateTime(str, RIGHT_SLASH_FORMAT_FULL);
        case "\\":
          return parseDateTime(str, LEFT_SLASH_FORMAT_FULL);
        default:
          return null;
      }
    }

    matcher = DATE_PATTERN.matcher(str);
    if (matcher.matches()) {
      return parseDateFromString(str).atStartOfDay();
    }

    matcher = TIME_PATTERN.matcher(str);
    if (matcher.matches()) {
      return parseTime(str, FORMAT_TIME).atDate(LocalDate.now());
    }

    throw new DateFormatException("格式不支持，无法解析成日期时间对象；原日期时间字符为[" + str + "]");
  }

  /**
   * 从字符串中解析日期，支持格式yyyy[-\/]MM[-\/]dd、yyyy[-\/]M[-\/]dd、yyyy[-\/]MM[-\/]d、yyyy[-\/]M[-\/]d
   *
   * @param dateString
   *     日期字符串
   *
   * @return 日期
   */
  public static LocalDate parseDateFromString(String dateString) {
    // 匹配yyyy[-\/]MM[-\/]dd格式
    Matcher matcher = FULL_DATE_PATTERN.matcher(dateString);
    if (matcher.matches()) {
      final String joinSymbol = matcher.group(1);
      switch (joinSymbol) {
        case "-":
          return parseDate(dateString, DASH_FORMAT_SHORT);
        case "/":
          return parseDate(dateString, RIGHT_SLASH_FORMAT_SHORT);
        case "\\":
          return parseDate(dateString, LEFT_SLASH_FORMAT_SHORT);
        default:
          String errMsg = String.format("不支持的分隔符，原日期字符串为[%s]", dateString);
          throw new DateFormatException(errMsg);
      }
    }

    // 匹配yyyy[-\/]M[-\/]dd格式
    matcher = SHORT_MONTH_DATE_PATTERN.matcher(dateString);
    if (matcher.matches()) {
      final String joinSymbol = matcher.group(1);
      switch (joinSymbol) {
        case "-":
          return parseDate(dateString, SHORT_MONTH_DASH_FORMAT);
        case "/":
          return parseDate(dateString, SHORT_MONTH_RIGHT_SLASH_FORMAT);
        case "\\":
          return parseDate(dateString, SHORT_MONTH_LEFT_SLASH_FORMAT);
        default:
          String errMsg = String.format("不支持的分隔符，原日期字符串为[%s]", dateString);
          throw new DateFormatException(errMsg);
      }
    }

    // 匹配yyyy[-\/]MM[-\/]d格式
    matcher = SHORT_DAY_DATE_PATTERN.matcher(dateString);
    if (matcher.matches()) {
      final String joinSymbol = matcher.group(1);
      switch (joinSymbol) {
        case "-":
          return parseDate(dateString, SHORT_DAY_DASH_FORMAT);
        case "/":
          return parseDate(dateString, SHORT_DAY_RIGHT_SLASH_FORMAT);
        case "\\":
          return parseDate(dateString, SHORT_DAY_LEFT_SLASH_FORMAT);
        default:
          String errMsg = String.format("不支持的分隔符，原日期字符串为[%s]", dateString);
          throw new DateFormatException(errMsg);
      }
    }

    // 匹配yyyy[-\/]M[-\/]d格式
    matcher = SHORT_MONTH_AND_DAY_DATE_PATTERN.matcher(dateString);
    if (matcher.matches()) {
      final String joinSymbol = matcher.group(1);
      switch (joinSymbol) {
        case "-":
          return parseDate(dateString, SHORT_MONTH_AND_DAY_DASH_FORMAT);
        case "/":
          return parseDate(dateString, SHORT_MONTH_AND_DAY_RIGHT_SLASH_FORMAT);
        case "\\":
          return parseDate(dateString, SHORT_MONTH_AND_DAY_LEFT_SLASH_FORMAT);
        default:
          String errMsg = String.format("不支持的分隔符，原日期字符串为[%s]", dateString);
          throw new DateFormatException(errMsg);
      }
    }

    throw new DateFormatException("格式不支持，无法解析成日期时间对象；原日期时间字符为[" + dateString + "]");
  }

  /**
   * 获取当前日期，返回整数
   *
   * @return 当前日期，格式为“yyyyMMdd”
   */
  public static int getCurrentDate() {

    String dateString = getCurrentDateToString(GF_DEFAULT_SHORT_FORMATTER);
    return Integer.parseInt(dateString);
  }

  public static String getCurrentDateToString(String format) {

    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
    return getCurrentDateToString(dateTimeFormatter);
  }

  public static String getCurrentDateToString(DateTimeFormatter dateTimeFormatter) {

    LocalDate localDate = LocalDate.now();
    return localDate.format(dateTimeFormatter);
  }

  /**
   * 获取当前时间，返回整数
   *
   * @return 当前时间，格式为“hhmmss"
   */
  public static int getCurrentTime() {

    LocalTime localTime  = LocalTime.now();
    String    timeString = localTime.format(GF_DEFAULT_TIME_FORMATTER);
    return Integer.parseInt(timeString);
  }

  public static String format(int date, DateTimeFormatter dateTimeFormatter) {

    LocalDate localDate = LocalDate.parse(String.valueOf(date), GF_DEFAULT_SHORT_FORMATTER);
    return localDate.format(dateTimeFormatter);
  }

  public static String format(int date, String formatString) {

    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatString);
    return format(date, dateTimeFormatter);
  }

  /**
   * 获取一个日期是这个月的第几天
   *
   * @param date
   *     日期
   *
   * @return 这个月的第几天
   */
  public static int getDayOfMonth(int date) {

    LocalDate localDate = parseDate(date, GF_DEFAULT_SHORT);
    return localDate.getDayOfMonth();
  }

  /**
   * 获取一个日期是一年的第几天
   *
   * @param date
   *     日期
   *
   * @return 一年的第几天
   */
  public static int getDayOfYear(int date) {

    LocalDate localDate = parseDate(date, GF_DEFAULT_SHORT);
    return localDate.getDayOfYear();
  }

  /**
   * 获取一个日期是一个星期的第几天
   *
   * @param date
   *     日期
   *
   * @return 一个星期的第几天
   */
  public static int getDayOfWeek(int date) {

    LocalDate localDate = parseDate(date, GF_DEFAULT_SHORT);
    return localDate.getDayOfWeek().getValue();
  }

  /**
   * 获取日期对应的月份
   *
   * @param date
   *     日期
   *
   * @return 该日期对应的月份
   */
  public static int getMonth(int date) {

    LocalDate localDate = parseDate(date, GF_DEFAULT_SHORT);
    return localDate.getMonthValue();
  }

  /**
   * 获取日期对应的年份
   *
   * @param date
   *     日期
   *
   * @return 该日期对应的年份
   */
  public static int getYear(int date) {

    LocalDate localDate = parseDate(date, GF_DEFAULT_SHORT);
    return localDate.getYear();
  }

}